package com.osce.ex.service.tools;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.csce.domain.entity.exam.ExQuestinOption;
import com.csce.domain.entity.exam.ExQuestion;
import com.csce.domain.entity.exam.vo.Checked;
import com.csce.domain.entity.exam.vo.ExExamQuestion;
import com.csce.domain.entity.exam.vo.ExStatus;
import com.doudou.core.container.ListUtil;
import com.doudou.core.container.MapUtil;
import com.doudou.core.lang.ObjUtil;
import com.doudou.core.str.StrUtil;
import com.osce.common.constant.CacheConstants;
import com.osce.common.exception.ServiceException;
import com.osce.interfaces.ex.IExQuestionService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zzxjs
 * @since 2023/8/8
 * 封装一些题目的统一方法
 */
@Service
public class ExService {
    private final static Log log = LogFactory.get(ExService.class);

    @Resource
    private IExQuestionService questionService;

    private static final String RADIO_FORMAT = "[{}]";

    /**
     * 根据策略随机分配题目
     *
     * @param sig           策略
     * @param checkeds      选中的范畴
     * @param questionCount 总题数
     * @return 计算后的没张表需要查询的条数，将随机交给数据库
     */
    public Map<Integer, Integer> analyseSig(String sig, List<Checked> checkeds, Integer questionCount) {
        Map<Integer, Integer> map = MapUtil.map(false);
        //分析用户需求
        if (CollUtil.isEmpty(checkeds)) {
            throw new ServiceException("请选择范畴");
        }
        int size = checkeds.size();
        if (size == 1) {
            map.put(checkeds.get(0).getTopic(), questionCount);
        } else {
            if (CacheConstants.RATIO.equals(sig)) {//按范畴比例
                Map<Integer, Integer> dbQuestions = new HashMap<>();//范畴下的总题数
                Integer dbTotal = 0;//遍历范畴条数
                Integer total;
                for (Checked checked : checkeds) {
                    total = questionService.selectCountByTopic(checked.getTopic());
                    dbQuestions.put(checked.getTopic(), total);
                    dbTotal += total;
                }
                //计算题目数量占比
                for (Integer topic : dbQuestions.keySet()) {
                    Integer count = dbQuestions.get(topic);
                    Double ratio = Double.valueOf(NumberUtil.formatPercent(count * 1.0 / dbTotal, 3).replace("%", ""));
                    //计算题目数量
                    map.put(topic, NumberUtil.round(questionCount * (ratio / 100), 0).intValue());
                }
            } else if (CacheConstants.AVERAGE.equals(sig)) {//平均选择
                Integer half = questionCount / size;
                for (Checked checked : checkeds) {
                    map.put(checked.getTopic(), half);
                }
                //判断是否有余数，如果有余数，补给第一个范畴
                int remainder = questionCount % size;
                if (remainder != 0) {
                    Integer first = map.keySet().iterator().next();
                    map.put(first, map.get(map.keySet().iterator().next()) + remainder);
                }
            } else if (CacheConstants.OPTIONAL.equals(sig)) {//自选
                for (Checked checked : checkeds) {
                    map.put(checked.getTopic(), checked.getNumber());
                }
            } else {
                throw new ServiceException("策略选择有误");
            }
        }
        //随机获取题目编号
        List<Long> questionIds = questionService.randomIdsByTopic(map);
        return map;
    }

    /**
     * 判断题目是否正确
     *
     * @param exId    题目的编号，无论是练习还是考试
     * @param ids     题目编号集合
     * @param answers 答案集合
     */
    public ExStatus judge(Long exId, List<Long> ids, Map<Long, Object> answers) {
        ExStatus exStatus = new ExStatus();
        ExExamQuestion exExamQuestion;
        ExQuestion question;//题目
        List<Long> answer;//答案
        List<Long> rightAnswer;//正确答案
        for (Long questionId : ids) {
            question = questionService.selectExQuestionById(questionId);
            //格式化用户答题答案
            answer = parseAnswer(question.getType(), answers.get(questionId));
            //格式化正确答案
            rightAnswer = parseRightAnswer(question.getExQuestinOptionList());
            exExamQuestion = ExExamQuestion.builder().
                    examId(exId).
                    questionId(questionId).//题目
                            answers(answer).//填充答案
                            isRight(ListUtil.equalUsSet(answer, rightAnswer) ? 1 : 2).//判断是否做对
                            build();
            exStatus.addExamQuestionList(exExamQuestion);//填充状态
        }
        return exStatus.calculate(ids.size());
    }

    /**
     * 格式化答案
     *
     * @param questionType 题目类型
     * @param answer       用户答题  32   /   [32,33]
     * @return 32=>[32]  /   [32,33]
     */
    private List<Long> parseAnswer(Integer questionType, Object answer) {
        try {
            if (ObjUtil.isEmpty(answer)) {
                return ListUtil.arrayList();
            }
            /* 1单选，使用 [] 包裹后转
             * 2多选，直接转
             */
            return JSONUtil.toList(questionType == 1 ? StrUtil.format(RADIO_FORMAT, answer) : answer.toString(), Long.class);
        } catch (Exception e) {
            log.error(e, "格式化答案失败，{}选题，答案：{}", questionType == 1 ? '单' : '多', answer);
        }
        return ListUtil.arrayList();
    }

    /**
     * 格式化正确答案
     *
     * @param options 选项
     * @return [32, 33]
     */
    private List<Long> parseRightAnswer(List<ExQuestinOption> options) {
        return options.stream().filter(o -> o.getRight().equals(1)).map(ExQuestinOption::getId).collect(Collectors.toList());
    }

    /**
     * 打乱题目id顺序
     */
    public List<Long> disruptOrder(List<Long> questions) {
        return ListUtil.disrupt(questions);
    }

}












